using System;
using System.Text;
using NHibernate;
using System.Collections.Generic;

namespace Technoera.Common.Nh
{
    public class NhHelper
    {
        public static void TryCloseAndDispose(ISession session)
        {
            try
            {
                if (session.IsOpen)
                {
                    session.Close();
                }
                session.Dispose();
            }
            catch
            {
                //TODO: Log error
            }
        }

        #region Read

        public static IList<T> GetList<T>(ISession session, ICriteria criteria)
        {
            if (session.Transaction != null && session.Transaction.IsActive)
            {
                return criteria.List<T>();
            }
            else
            {
                using (ITransaction transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
                {
                    IList<T> result = criteria.List<T>();
                    transaction.Commit();
                    return result;
                }
            }
        }

        public static IList<T> GetList<T>(ISession session, IQuery query)
        {
            if (session.Transaction != null && session.Transaction.IsActive)
            {
                return query.List<T>();
            }
            else
            {
                using (ITransaction transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
                {
                    IList<T> result = query.List<T>();
                    transaction.Commit();
                    return result;
                }
            }
        }

        public static T GetUniqueResult<T>(ISession session, IQuery query)
        {
            if (session.Transaction != null && session.Transaction.IsActive)
            {
                return GetUniqueResult<T>(query);
            }
            else
            {
                using (ITransaction transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
                {
                    T result = GetUniqueResult<T>(query);
                    transaction.Commit();
                    return result;
                }
            }
        }

        private static T GetUniqueResult<T>(IQuery query)
        {
            object result = query.UniqueResult(); //UniqueResult<T> contains a bug... :-(
            if (result == null)
            {
                return default(T);
            }
            else
            {
                return (T)result;
            }
        }

        public static T GetUniqueResult<T>(ISession session, ICriteria criteria)
        {
            if (session.Transaction != null && session.Transaction.IsActive)
            {
                return GetUniqueResult<T>(criteria);
            }
            else
            {
                using (ITransaction transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
                {
                    T result = GetUniqueResult<T>(criteria);
                    transaction.Commit();
                    return result;
                }
            }
        }

        private static T GetUniqueResult<T>(ICriteria criteria)
        {
            object result = criteria.UniqueResult(); //Actually UniqueResult<T> seems to contain a bug... :-(
            if (result == null)
            {
                return default(T);
            }
            else
            {
                return (T)result;
            }
        }

        #endregion

        #region Write

        public static void Insert<T>(T entity, ISession session)
        {
            if (session.Transaction != null && session.Transaction.IsActive)
            {
                session.Save(entity);
                session.Flush();
            }
            else
            {
                using (ITransaction transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
                {
                    try
                    {
                        session.Save(entity);
                        session.Flush();
                        transaction.Commit();
                    }
                    catch
                    {
                        transaction.Rollback();
                        throw;
                    } 
                }
            }
        }

        public static void Update<T>(T entity, ISession session)
        {
            if (session.Transaction != null && session.Transaction.IsActive)
            {
                session.Update(entity);
                session.Flush();
            }
            else
            {
                using (ITransaction transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
                {
                    try
                    {
                        session.Update(entity);
                        session.Flush();
                        transaction.Commit();
                    }
                    catch
                    {
                        transaction.Rollback();                            
                        throw;
                    }
                }
            }
        }

        public static void InsertOrUpdate<T>(T entity, ISession session)
        {
            if (session.Transaction != null && session.Transaction.IsActive)
            {
                session.SaveOrUpdate(entity);
                session.Flush();
            }
            else
            {
                using (ITransaction transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
                {
                    try
                    {
                        session.SaveOrUpdate(entity);
                        session.Flush();
                        transaction.Commit();
                    }
                    catch
                    {
                        transaction.Rollback();                            
                        throw;
                    }
                }
            }
        }

        public static void Delete<T>(T entity, ISession session)
        {
            if (session.Transaction != null && session.Transaction.IsActive)
            {
                session.Delete(entity);
                session.Flush();
            }
            else
            {
                using (ITransaction transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
                {
                    try
                    {
                        session.Delete(entity);
                        session.Flush();
                        transaction.Commit();
                    }
                    catch
                    {
                        transaction.Rollback();                            
                        throw;
                    }
                }
            }
        }

        #endregion
    }
}
